/**
  Generated main.c file from MPLAB Code Configurator

  @Company
    Microchip Technology Inc.

  @File Name
    main.c

  @Summary
    This is the generated main.c using PIC24 / dsPIC33 / PIC32MM MCUs.

  @Description
    This source file provides main entry point for system initialization and application code development.
    Generation Information :
        Product Revision  :  PIC24 / dsPIC33 / PIC32MM MCUs - 1.171.1
        Device            :  dsPIC33CK256MP505
    The generated drivers are tested against the following:
        Compiler          :  XC16 v1.70
        MPLAB 	          :  MPLAB X v5.50
*/

/*
    (c) 2020 Microchip Technology Inc. and its subsidiaries. You may use this
    software and any derivatives exclusively with Microchip products.

    THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
    EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
    WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
    PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
    WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.

    IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
    INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
    WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
    BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
    FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
    ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
    THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.

    MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
    TERMS.
*/

/**
  Section: Included Files
*/
#include "mcc_generated_files/system.h"
#include "mcc_generated_files/mcc.h"
#include "v_loop.h"
#include "app/gui/App_GUI .h"
#include "app/X2CScope/X2CScope.h"


//------------------------------------------------------------------------------
// Constants and Macro Definitions
#define AN13_VBUCK_SCALE (float)(1.0/2.0     * 4095.0/3.3 )  // ADC scaling buck output voltage
#define VBUCK_REF   (int16_t)( 3.3      * AN13_VBUCK_SCALE)  // Output votlage set value: 3.3V
#define VBUCK_RAMP  (int16_t)( 10e-3    * AN13_VBUCK_SCALE)
#define VBUCK_OV    (int16_t)( 3.6      * AN13_VBUCK_SCALE)
#define VBUCK_OV_RC (int16_t)( 3.5      * AN13_VBUCK_SCALE)
#define VBUCK_UV    (int16_t)( 3.0      * AN13_VBUCK_SCALE)
#define VBUCK_UV_RC (int16_t)( 3.1      * AN13_VBUCK_SCALE)

#define AN12_VIN_SCALE   (float)( 1.0/8.0    * 4095.0/3.3 ) // ADC scaling input voltage
#define VIN_TH_ON   (int16_t)( 6.5      * AN12_VIN_SCALE)    // Switch-on threshold: 6.5V
#define VIN_TH_OFF  (int16_t)( 5.5      * AN12_VIN_SCALE)    // Switch-off (under voltage) threshold: 5.5V

#define ADC_REFERENCE               3.3             // 3.3 Volts ==> maximum ADC-Value
#define VIN_ADC_RESOLUTION          4095UL          // 12 bits
#define BUCK_VIN_FEEDBACK_GAIN      0.1253          // 1k /(1k+6.98k)
#define BUCK_ADC_RESOLUTION         4095UL          // 12 bits
#define BUCK_VOUT_FEEDBACK_GAIN     0.5             // 1k /(1k+1k)
#define BUCK_ISNS_FEEDBACK_GAIN     1.0             // Current Gain in V/A

#define TMR1_1MS_TICKER     10
#define TMR1_500MS_TICKER   5000
#define TMR1_200MS_DELAY    2000

#define OutputVoltageLow    0x1;    // fault_status -> bit0
#define OutputVoltageHigh   0x2;    // fault_status -> bit1

//------------------------------------------------------------------------------
// Define Global Variables:
uint16_t count_1ms = 0;
uint16_t count_500ms = 0;

uint16_t tick_1ms = 0;
uint16_t tick_500ms = 0;
uint16_t tick_100us = 0;

int16_t vbuck_ref = 0;
int16_t vbuck_adc = 0;
int16_t vin_adc = 0;
int16_t isns = 0;

uint16_t fsm_state = 0;
uint16_t start_tmr = 0;
uint16_t fault_status = 0;

/*******************************************************************************

*******************************************************************************/
void TMR1_CallBack(void)
{
    int16_t vout_ref;
    uint16_t power_on_off;
    /*********tick manage******************/
    tick_100us = 1;
    
    if (++count_1ms >= TMR1_1MS_TICKER)
    {
        tick_1ms = 1;
        count_1ms = 0;
    }
    
    if (++count_500ms >= TMR1_500MS_TICKER)
    {
        tick_500ms = 1;
        count_500ms = 0;
    }
     
    /*********fault manage*****************/
    if (vbuck_adc > VBUCK_OV)               // 3.6V
    {
        fault_status |= OutputVoltageHigh;
    }
    else if (vbuck_adc <= VBUCK_OV_RC)      // 3.5V      
    {
        fault_status &= ~OutputVoltageHigh;
    }

    if (vbuck_adc < VBUCK_UV)               // 3.0V
    {
        fault_status |= OutputVoltageLow;
    }
    else if (vbuck_adc >= VBUCK_UV_RC)      // 3.1V    
    {
        fault_status &= ~OutputVoltageLow;
    }
    
    /*********power on/off manage**********/
    power_on_off = GetBuckPowerOnOffFromGui();

    switch(fsm_state)
    {
        case 0:     // State 0: wait for Vin>threshold (delay time)
        {
            if ((vin_adc < VIN_TH_ON) || (power_on_off == 0))
            {
                start_tmr = 0;
            }
            else if ((++start_tmr > TMR1_200MS_DELAY) && (power_on_off == 1))
            {                
                fsm_state = 1;                
                vbuck_ref = 0;
                
                PG1IOCONLbits.OVRENL = 0;
                PG1IOCONLbits.OVRENH = 0;                
                v_loop.status.bits.enabled = true;
            }
            
            break;
        }
        case 1:     // State 1: ramp up buck reference value (soft-start)
        {            
            vout_ref = GetBuckVoutRefFromGui();
            
            if (vbuck_ref < vout_ref)
            {
                vbuck_ref += VBUCK_RAMP;
            }
            else if (vbuck_ref > vout_ref)
            {
                vbuck_ref -= VBUCK_RAMP;
            }
            else
            {
                vbuck_ref = vout_ref;
            }
            
            if ((vin_adc < VIN_TH_OFF) || (power_on_off == 0))
            {
                start_tmr = 0;
                vbuck_ref = 0;
                fsm_state = 0;

                PG1IOCONLbits.OVRENL = 1; 
                PG1IOCONLbits.OVRENH = 1;                 
                v_loop.status.bits.enabled = false;
                v_loop_Reset(&v_loop);
            }
                        
            break;
        }
    }
}

/*******************************************************************************

*******************************************************************************/
void __attribute__ ( ( __interrupt__ , auto_psv, context ) ) _ADCAN13Interrupt ( void )
{
    vin_adc = ADCBUF12;    
    vbuck_adc = ADCBUF13;        
    isns = ADCBUF0;
    
    v_loop_Update(&v_loop);
    PG1STATbits.UPDREQ = 1;

    //clear the channel_AN13 interrupt flag
    IFS6bits.ADCAN13IF = 0;
}

/*******************************************************************************

*******************************************************************************/
void CONTROL_Initialize(void)
{

    v_loop_Initialize(&v_loop);    

    v_loop.Ports.ptrControlReference = (uint16_t *)&vbuck_ref;
    v_loop.Ports.Source.ptrAddress = (uint16_t *)&vbuck_adc;
    v_loop.Ports.Target.ptrAddress = (uint16_t *)&PG1DC;

    v_loop.ADCTriggerControl.ptrADCTriggerBRegister = &PG1TRIGB;
    v_loop.ADCTriggerControl.ADCTriggerBOffset = 0;     

    v_loop.Limits.MinOutput = 10;
    v_loop.Limits.MaxOutput = (uint16_t)(0.8*PG1PER);
    
    v_loop.status.bits.enabled = false; // Keep controller enabled

}

/*******************************************************************************

*******************************************************************************/
uint16_t GetBuckOutputVoltage(void)
{
    return (uint16_t)(((uint32_t)vbuck_adc * ADC_REFERENCE * 100) / (BUCK_VOUT_FEEDBACK_GAIN * BUCK_ADC_RESOLUTION));
}

/*******************************************************************************

*******************************************************************************/
uint16_t GetBuckInputVoltage(void)
{
    return (uint16_t)(((uint32_t)vin_adc * ADC_REFERENCE * 100) / (BUCK_VIN_FEEDBACK_GAIN * VIN_ADC_RESOLUTION));
}

/*******************************************************************************

*******************************************************************************/
uint16_t GetBuckInductorCurrent(void)
{
    return (uint16_t)(((uint32_t)isns * ADC_REFERENCE * 100) / (BUCK_ISNS_FEEDBACK_GAIN * VIN_ADC_RESOLUTION));
}

/*******************************************************************************

*******************************************************************************/
uint16_t GetBuckFalultStatus(void)
{
    return fault_status;
}

/*******************************************************************************

*******************************************************************************/
int main(void)
{
    // initialize the device
    SYSTEM_Initialize();
    CONTROL_Initialize();
    App_GUI_Init();    
    X2CScope_Init();
    
    INTERRUPT_GlobalEnable(); 
    TMR1_Start();
    PWM_GeneratorEnable(PWM_GENERATOR_1);
    
    while (1)
    {
        // Add your application code
        if (tick_100us == 1)
        {
            Dev_GuiComm_Task_100us();
            Dev_GuiComm_Scope_Record_2CH( GetBuckInputVoltage(),
                                          GetBuckOutputVoltage());    

            X2CScope_Update();       
            
            tick_100us = 0;
        }
        
        if (tick_1ms == 1)
        {
            App_GUI_Task_1ms();
            X2CScope_Communicate();
            
            tick_1ms = 0;                        
        }        
        
        if (tick_500ms == 1)
        {
            IO_RB6_Toggle();    // blink LED 1Hz                    
            
            tick_500ms = 0;
        }
        
        X2CScope_Communicate();
    }
    return 1; 
}

/**
 End of File
*/

